package com.kgc.sbt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.kgc.sbt.api.BuyLimitApi;
import com.kgc.sbt.api.OrderApi;
import com.kgc.sbt.config.annotation.RequestPermission;
import com.kgc.sbt.constant.SystemConstant;
import com.kgc.sbt.domain.NoticeLimit;
import com.kgc.sbt.service.BuyLimitService;
import com.kgc.sbt.util.RedisUtils;
import com.kgc.sbt.util.RequestResult;
import com.kgc.sbt.util.ResultBuildUtil;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created on 2021/6/21.
 * <p>
 * Author: GongMingJie
 * <p>
 * Description: 抢购业务入口
 */
@RestController
@Slf4j
@Api(tags = "抢购活动操作接口，版本号：1.0.0")
@RequestPermission
public class BuyLimitController {

    @Reference
    private BuyLimitApi buyLimitApi;

    @Autowired
    private BuyLimitService buyLimitService;

    @Reference
    private OrderApi orderApi;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * Created on 2021/6/22
     * Author: GongMingJie
     * @param limitBuyId
     * @return
     * Description: 用户登记抢购活动，需要加自定义注解，判断用户是否登录
     */
    @PostMapping("/registerLimitBuy")
    @ApiOperation(value = "用户登记抢购活动",notes = "需要传入活动id，用户id")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "limitBuyId",required = true,value = "抢购活动id",defaultValue = "3",paramType = "query")
    })
    @ApiResponses({
            @ApiResponse(code = 9000,message = "传入参数不完整"),
            @ApiResponse(code = 9001,message = "登记失败"),
            @ApiResponse(code = 9002,message = "没有此抢购活动"),
            @ApiResponse(code = 9003,message = "活动已开始，无法预约"),
            @ApiResponse(code = 0000,message = "用户id登记抢购活动id成功"),
    })
    public RequestResult<String> registerLimitBuy(@RequestParam String limitBuyId, HttpServletRequest request){

        // 校验权限，是否已经登录
        String token = request.getHeader("token");

        // 校验token是否有效
        Integer userId = (Integer) redisUtils.get(token);

        NoticeLimit noticeLimit = new NoticeLimit();

        noticeLimit.setUserId(userId);
        noticeLimit.setLimitBuyId(Integer.valueOf(limitBuyId));

        // 判断是否传入用户id和抢购活动id
        log.info("------ 从前台获取的登记用户：{}，抢购活动：{}",noticeLimit.getUserId(),noticeLimit.getLimitBuyId());

        if (noticeLimit.getLimitBuyId()!=null){
            // 判断是否有此抢购活动
            if (buyLimitApi.getLimitBuy(noticeLimit.getLimitBuyId()) != null){

                // 判断是否开始
                if(!redisUtils.hasKey("buyLimitStart" + limitBuyId)){
                    return ResultBuildUtil.fail("9003","活动已开始，无法预约");
                }

                // 判断是否结束
                if(!redisUtils.hasKey("buyLimitEnd" + limitBuyId)){
                    return ResultBuildUtil.fail("9004","活动已结束");
                }

                // 调用抢购活动模块，将数据入库
                if (buyLimitApi.createNoticeLimit(noticeLimit)){
                    return ResultBuildUtil.success("用户" + noticeLimit.getUserId() + "登记抢购活动" + noticeLimit.getLimitBuyId() + "成功");
                }else {
                    return ResultBuildUtil.fail("9001","登记失败");
                }
            }else {
                return ResultBuildUtil.fail("9002","没有此抢购活动");
            }
        }else {
            return ResultBuildUtil.fail("9000","传入数据不完整");
        }
    }

    /**
     * Created on 2021/6/23
     * Author: GongMingJie
     * @param buyCount 商品数量
     * @param buyLimitId 抢购活动id
     * @param addressId 地址id
     * @return
     * Description: 开始抢购
     */
    @PostMapping("/buylimit")
    @ApiOperation(value = "抢购活动开始",notes = "需要传入用户、商品数量、抢购活动、地址")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "buyCount",required = true,value = "购买商品数量",paramType = "query",defaultValue = "1"),
            @ApiImplicitParam(name = "buyLimitId",required = true,value = "抢购活动id",paramType = "query"),
            @ApiImplicitParam(name = "addressId",required = true,value = "地址id",paramType = "query")
    })
    @ApiResponses({
            @ApiResponse(code = 9001,message = "您未登记，无法抢购！"),
            @ApiResponse(code = 9002,message = "抢购活动还未开始！"),
            @ApiResponse(code = 9003,message = "抢购活动已经结束！"),
            @ApiResponse(code = 9004,message = "抢购失败，同一个商品，同一个用户只能抢购一次！"),
            @ApiResponse(code = 9005,message = "抢购失败，库存不足！"),
            @ApiResponse(code = 4001,message = "效参数（商品与数量非法）！"),
            @ApiResponse(code = 4002,message = "缺失必要参数！"),
            @ApiResponse(code = 4003,message = "无效参数(优惠券非法)！"),
            @ApiResponse(code = 4004,message = "优惠券不可用！"),
            @ApiResponse(code = 4005,message = "优惠券无效！"),
            @ApiResponse(code = 4006,message = "非法参数！"),
            @ApiResponse(code = 0000,message = "抢购成功，生成的订单号为：T202111201201200，价格为：23.00！")
    })
    public RequestResult<String> buylimit(HttpServletRequest request, @RequestParam(defaultValue = "1") Integer buyCount, @RequestParam Integer buyLimitId, @RequestParam Integer addressId){

        // 校验权限，是否已经登录
        String token = request.getHeader("token");

        // 校验token是否有效
        Integer userId = (Integer) redisUtils.get(token);

        // 先判断此人是否登记
        if(!buyLimitApi.isRegister(userId,buyLimitId)){
            return ResultBuildUtil.fail("9001","您未登记，无法抢购！");
        }

        // 判断抢购活动是否开启
        if ((buyLimitApi.getBuyLimitStartTime(buyLimitId).getTime() - System.currentTimeMillis()) > 0){
            return ResultBuildUtil.fail("9002","抢购活动还未开始！");
        }

        // 判断抢购活动是否结束
        if ((buyLimitApi.getBuyLimitEndTime(buyLimitId).getTime() - System.currentTimeMillis()) < 0){
            return ResultBuildUtil.fail("9003","抢购活动已经结束！");
        }

        // 获取此抢购活动所对应的商品id
        String goodsId = buyLimitApi.getGoodsId(buyLimitId).toString();

        // 获取此抢购活动所对应的商品价格
        BigDecimal price = buyLimitApi.getGoodsPrice(buyLimitId);

        // 初始化商品库存到redis，实际开发中这个是在商品上架处理
        if(!buyLimitService.initGoodsStockToRedis(goodsId)){
            log.warn("------ 初始化商品{}的库存失败或者已经初始化 ------", goodsId);
        }

        // 锁定用户，同一个用户，在整个抢购过程中，只能抢购一次
        if(!buyLimitService.lockBuyUser(userId.toString(), goodsId,buyLimitId)){
            log.info("------ 用户{}, 商品{}, 只能抢购一次 ------", userId, goodsId);
            return ResultBuildUtil.fail("9004","抢购失败，同一个商品，同一个用户只能抢购一次！");
        }

        // 校验库存，如果库存不足，直接抢购失败
        if(!buyLimitService.checkProdStock(goodsId, buyCount)){
            log.info("------ 商品{}, 库存不足 ------", goodsId);
            return ResultBuildUtil.fail("9005","抢购失败，库存不足！");
        }

        // 锁库存，如果当前库存已经被其他用户锁定，不可以继续，必须持续等待解锁
        while(true){
            // 判断库存锁是否释放，只有拿到库存锁，才可以执行抢购(防止库存锁释放失败，导致程序终端，切记，锁库存要加超时时间)
            if(!buyLimitService.isStockLock(goodsId)){
                break;
            }
        }

        // 生成订单号
        String tradeOrderNo = "T" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()) + UUID.randomUUID().toString().replace("-", "").substring(0,5);

        // 将订单存入redis
        // buyLimitService.setTradeOrderNo2Redis(userId, tradeOrderNo);

        // TODO 调用订单接口，生成订单，发送消息队列，异步处理
        Integer[] goodsIds = {Integer.valueOf(goodsId)};
        Integer[] buyCounts = {buyCount};
        // TODO，还需传一个price
        RequestResult<String> requestResult = orderApi.createOrder(userId, addressId, 0, goodsIds,buyCounts ,tradeOrderNo,price);

        if (requestResult.getCode().equals(SystemConstant.SYS_RESP_SUCCESS_CODE)){
            // 订单生成成功
            // redis减库存
            buyLimitService.subProdStockNum(goodsId, buyCount);

            // 释放库存锁
            buyLimitService.unlockProdStockLock(goodsId);

            Map<String, Object> returnMap = new HashMap<>();

       /*     returnMap.put("结果","抢购成功");
            returnMap.put("订单号", tradeOrderNo);
            returnMap.put("价格", price);*/

            return ResultBuildUtil.success("抢购成功，生成的订单号为： " + tradeOrderNo + " ,价格为：" + price);

        }else {
            // 订单生成失败
            return requestResult;
        }

        // 等待订单生成功
        /*while(true){
            // 判断订单是否生成成功，redis中没有，代表已经生成
            if(buyLimitService.isTradeOrderCreated(tradeOrderNo)){
                break;
            }
        }*/

    }
}
